<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Hunspell 词干提取器 | Elasticsearch: 权威指南 | Elastic</title>
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
</head>
<body>
<div class="main-container">
    <section id="content">
        
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原文地址: <a href="https://www.elastic.co/guide/cn/elasticsearch/guide/current/hunspell.html" rel="nofollow">https://www.elastic.co/guide/cn/elasticsearch/guide/current/hunspell.html</a>, 版权归 www.elastic.co 所有<br/>
                            英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/hunspell.html" rel="nofollow">https://www.elastic.co/guide/en/elasticsearch/guide/current/hunspell.html</a>
                            </div>
                        <!-- start body -->
                  <div class="page_header">
<b>请注意:</b><br>本书基于 Elasticsearch 2.x 版本，有些内容可能已经过时。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: 权威指南</a></span>
»
<span class="breadcrumb-link"><a href="languages.html">处理人类语言</a></span>
»
<span class="breadcrumb-link"><a href="stemming.html">将单词还原为词根</a></span>
»
<span class="breadcrumb-node">Hunspell 词干提取器</span>
</div>
<div class="navheader">
<span class="prev">
<a href="dictionary-stemmers.html">« 字典词干提取器</a>
</span>
<span class="next">
<a href="choosing-a-stemmer.html">选择一个词干提取器 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="hunspell"></a>Hunspell 词干提取器<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/230_Stemming/30_Hunspell_stemmer.asciidoc">edit</a>
</h2>
</div></div></div>
<p>Elasticsearch 提供了基于词典提取词干的

<a href="https://www.elastic.co/guide/en/elasticsearch/reference/5.6/analysis-hunspell-tokenfilter.html" class="ulink" target="_top"><code class="literal">hunspell</code> 语汇单元过滤器（token filter）</a>.
Hunspell <a href="http://hunspell.github.io/" class="ulink" target="_top"><em>hunspell.github.io</em></a> 是一个 Open Office、LibreOffice、Chrome、Firefox、Thunderbird 等众多其它开源项目都在使用的拼写检查器。</p>
<p>可以从这里获取 Hunspell 词典 ：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
<a href="http://extensions.openoffice.org/" class="ulink" target="_top"><em>extensions.openoffice.org</em></a>: 下载解压 <code class="literal">.oxt</code> 后缀的文件。
</li>
<li class="listitem">
<a href="http://mzl.la/157UORf" class="ulink" target="_top"><em>addons.mozilla.org</em></a>: 下载解压 <code class="literal">.xpi</code> 扩展文件。
</li>
<li class="listitem">
<a href="http://download.services.openoffice.org/contrib/dictionaries/" class="ulink" target="_top">OpenOffice archive</a>: 下载解压 <code class="literal">.zip</code> 文件。
</li>
</ul>
</div>
<p>一个 Hunspell 词典由两个文件组成 — 具有相同的文件名和两个不同的后缀 — 如
<code class="literal">en_US</code>—和下面的两个后缀的其中一个：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
<code class="literal">.dic</code>
</span>
</dt>
<dd>
包含所有词根，采用字母顺序，再加上一个代表所有可能前缀和后缀的代码表 【集体称之为词缀( <em>affixes</em> 】
</dd>
<dt>
<span class="term">
<code class="literal">.aff</code>
</span>
</dt>
<dd>
包含实际 <code class="literal">.dic</code> 文件每一行代码表对应的前缀和后缀转换
</dd>
</dl>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_安装一个词典"></a>安装一个词典<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/230_Stemming/30_Hunspell_stemmer.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Hunspell 语汇单元过滤器在特定的 Hunspell 目录里寻找词典，
默认目录是 <code class="literal">./config/hunspell/</code> 。 <code class="literal">.dic</code> 文件和 <code class="literal">.aff</code> 文件应该要以子目录且按语言/区域的方式来命名。
例如，我们可以为美式英语创建一个 Hunspell 词干提取器，目录结构如下：</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">config/
  └ hunspell/ <a id="CO156-1"></a><i class="conum" data-value="1"></i>
      └ en_US/ <a id="CO156-2"></a><i class="conum" data-value="2"></i>
          ├ en_US.dic
          ├ en_US.aff
          └ settings.yml <a id="CO156-3"></a><i class="conum" data-value="3"></i></pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO156-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Hunspell 目录位置可以通过编辑 <code class="literal">config/elasticsearch.yml</code> 文件的：
<code class="literal">indices.analysis.hunspell.dictionary.location</code> 设置来修改。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO156-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">en_US</code> 是这个区域的名字，也是我们传给 <code class="literal">hunspell</code> 语汇单元过滤器参数 <code class="literal">language</code> 值。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO156-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p>一个语言一个设置文件，下面的章节会具体介绍。</p>
</td>
</tr>
</table>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_按语言设置"></a>按语言设置<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/230_Stemming/30_Hunspell_stemmer.asciidoc">edit</a>
</h3>
</div></div></div>
<p>在语言的目录设置文件 <code class="literal">settings.yml</code> 包含适用于所有字典内的语言目录的设置选项。</p>
<div class="pre_wrapper lang-yaml">
<pre class="programlisting prettyprint lang-yaml">---
ignore_case:          true
strict_affix_parsing: true</pre>
</div>
<p>这些选项的意思如下：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
<code class="literal">ignore_case</code>
</span>
</dt>
<dd>
<p>Hunspell 目录默认是区分大小写的，如，姓氏 <code class="literal">Booker</code> 和名词 <code class="literal">booker</code> 是不同的词，所以应该分别进行词干提取。
也许让 <code class="literal">hunspell</code> 提取器区分大小写是一个好主意，不过也可能让事情变得复杂：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
一个句子的第一个词可能会被大写，因此感觉上会像是一个名词。
</li>
<li class="listitem">
输入的文本可能全是大写，如果这样那几乎一个词都找不到。
</li>
<li class="listitem">
用户也许会用小写来搜索名字，在这种情况下，大写开头的词将找不到。
</li>
</ul>
</div>
<p>一般来说，设置参数 <code class="literal">ignore_case</code> 为 <code class="literal">true</code> 是一个好主意。</p>
</dd>
<dt>
<span class="term">
<code class="literal">strict_affix_parsing</code>
</span>
</dt>
<dd>
词典的质量千差万别。 一些网上的词典的 <code class="literal">.aff</code> 文件有很多畸形的规则。
默认情况下，如果 Lucene 不能正常解析一个词缀(affix)规则， 它会抛出一个异常。
你可以通过设置 <code class="literal">strict_affix_parsing</code> 为 <code class="literal">false</code> 来告诉 Lucene 忽略错误的规则。
</dd>
</dl>
</div>
<div class="sidebar">
<div class="titlepage"><div><div>
<p class="title"><strong>自定义词典</strong></p>
</div></div></div>
<p>如果一个目录放置了多个词典 (<code class="literal">.dic</code> 文件)，
他们会在加载时合并到一起。这可以让你以自定义的词典的方式对下载的词典进行定制：</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">config/
  └ hunspell/
      └ en_US/  <a id="CO157-1"></a><i class="conum" data-value="1"></i>
          ├ en_US.dic
          ├ en_US.aff <a id="CO157-2"></a><i class="conum" data-value="2"></i>
          ├ custom.dic
          └ settings.yml</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO157-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">custom</code> 词典和 <code class="literal">en_US</code> 词典将合并到一起。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO157-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>多个 <code class="literal">.aff</code> 文件是不允许的，因为会产生规则冲突。</p>
</td>
</tr>
</table>
</div>
<p><code class="literal">.dic</code> 文件和 <code class="literal">.aff</code> 文件的格式在这里讨论：
<a class="xref" href="hunspell.html#hunspell-dictionary-format" title="Hunspell 词典格式">Hunspell 词典格式</a> 。</p>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_创建一个_hunspell_语汇单元过滤器"></a>创建一个 Hunspell 语汇单元过滤器<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/230_Stemming/30_Hunspell_stemmer.asciidoc">edit</a>
</h3>
</div></div></div>
<p>一旦你在所有节点上安装好了词典，你就能像这样定义一个 <code class="literal">hunspell</code> 语汇单元过滤器：</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "en_US": {
          "type":     "hunspell",
          "language": "en_US" <a id="CO158-1"></a><i class="conum" data-value="1"></i>
        }
      },
      "analyzer": {
        "en_US": {
          "tokenizer":  "standard",
          "filter":   [ "lowercase", "en_US" ]
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO158-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>参数 <code class="literal">language</code> 和目录下对应的名称相同。</p>
</td>
</tr>
</table>
</div>
<p>你可以通过 <code class="literal">analyze</code> API 来测试这个新的分析器，
然后和 <code class="literal">english</code> 分析器比较一下它们的输出：</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">GET /my_index/_analyze?analyzer=en_US <a id="CO159-1"></a><i class="conum" data-value="1"></i>
reorganizes

GET /_analyze?analyzer=english <a id="CO159-2"></a><i class="conum" data-value="2"></i>
reorganizes</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO159-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>返回 <code class="literal">organize</code></p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO159-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>返回 <code class="literal">reorgan</code></p>
</td>
</tr>
</table>
</div>
<p>在前面的例子中，<code class="literal">hunspell</code> 提取器有一个有意思的事情，它不仅能移除前缀还能移除后缀。大多数算法词干提取仅能移除后缀。</p>
<div class="tip admon">
<div class="icon"></div>
<div class="admon_content">
<p>Hunspell 词典会占用几兆的内存。幸运的是，Elasticsearch 每个节点只会创建一个词典的单例。
所有的分片都会使用这个相同的 Hunspell 分析器。</p>
</div>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="hunspell-dictionary-format"></a>Hunspell 词典格式<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/230_Stemming/30_Hunspell_stemmer.asciidoc">edit</a>
</h3>
</div></div></div>
<p>尽管使用 <code class="literal">hunspell</code> 不必了解 Hunspell 词典的格式，
不过了解格式可以帮助我们编写自己的自定义的词典。其实很简单。</p>
<p>例如，在美式英语词典（US English dictionary），<code class="literal">en_US.dic</code> 文件包含了一个包含词 <code class="literal">analyze</code> 的实体，看起来如下：</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">analyze/ADSG</pre>
</div>
<p><code class="literal">en_US.aff</code> 文件包含了一个针对标记 <code class="literal">A</code> 、 <code class="literal">G</code> 、<code class="literal">D</code> 和 <code class="literal">S</code> 的前后缀的规则。
其中应该只有一个能匹配，每一个规则的格式如下：</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">[type] [flag] [letters to remove] [letters to add] [condition]</pre>
</div>
<p>例如，下面的后缀 (<code class="literal">SFX</code>) 规则 <code class="literal">D</code> 。它是说，当一个词由一个辅音 (除了 <code class="literal">a</code> 、<code class="literal">e</code> 、<code class="literal">i</code> 、<code class="literal">o</code> 或 <code class="literal">u</code> 外的任意音节)
 后接一个 <code class="literal">y</code> ，那么它可以移除 <code class="literal">y</code> 和添加 <code class="literal">ied</code> 结尾 （如，<code class="literal">ready</code> → <code class="literal">readied</code> ）。</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">SFX    D      y   ied  [^aeiou]y</pre>
</div>
<p>前面提到的 <code class="literal">A</code> 、 <code class="literal">G</code> 、<code class="literal">D</code> 和 <code class="literal">S</code> 标记对应规则如下：</p>
<div class="pre_wrapper lang-text">
<pre class="programlisting prettyprint lang-text">SFX D Y 4
SFX D   0     d          e <a id="CO160-1"></a><i class="conum" data-value="1"></i>
SFX D   y     ied        [^aeiou]y
SFX D   0     ed         [^ey]
SFX D   0     ed         [aeiou]y

SFX S Y 4
SFX S   y     ies        [^aeiou]y
SFX S   0     s          [aeiou]y
SFX S   0     es         [sxzh]
SFX S   0     s          [^sxzhy] <a id="CO160-2"></a><i class="conum" data-value="2"></i>

SFX G Y 2
SFX G   e     ing        e <a id="CO160-3"></a><i class="conum" data-value="3"></i>
SFX G   0     ing        [^e]

PFX A Y 1
PFX A   0     re         . <a id="CO160-4"></a><i class="conum" data-value="4"></i></pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO160-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">analyze</code> 以一个 <code class="literal">e</code> 结尾，所以它可以添加一个 <code class="literal">d</code> 变成 <code class="literal">analyzed</code> 。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO160-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">analyze</code> 不是由 <code class="literal">s</code> 、<code class="literal">x</code> 、<code class="literal">z</code> 、<code class="literal">h</code> 或 <code class="literal">y</code> 结尾，所以，它可以添加一个 <code class="literal">s</code> 变成 <code class="literal">analyzes</code> 。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO160-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">analyze</code> 以一个 <code class="literal">e</code> 结尾，所以，它可以移除 <code class="literal">e</code> 和添加 <code class="literal">ing</code> 然后变成 <code class="literal">analyzing</code> 。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO160-4"><i class="conum" data-value="4"></i></a></p>
</td>
<td align="left" valign="top">
<p>可以添加前缀 <code class="literal">re</code> 来形成 <code class="literal">reanalyze</code> 。这个规则可以组合后缀规则一起形成： <code class="literal">reanalyzes</code> 、<code class="literal">reanalyzed</code> 、
<code class="literal">reanalyzing</code> 。</p>
</td>
</tr>
</table>
</div>
<p>了解更多关于 Hunspell 的语法，可以前往 <a href="http://sourceforge.net/projects/hunspell/files/Hunspell/Documentation/" class="ulink" target="_top">Hunspell 文档</a> 。</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="dictionary-stemmers.html">« 字典词干提取器</a>
</span>
<span class="next">
<a href="choosing-a-stemmer.html">选择一个词干提取器 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>